package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.OrderMapper;
import com.sky.mapper.UserMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import org.apache.commons.lang.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author wfyn
 * @date 2023/10/9
 */
@Service
public class ReportServiceImpl implements ReportService {

    @Autowired
    OrderMapper orderMapper;
    @Autowired
    UserMapper userMapper;
    @Autowired
    WorkspaceService workspaceService;

    /**
     * 查询营业额统计
     *
     * @param begin
     * @param end
     * @return
     */
    public TurnoverReportVO getTurnoverStatistics(LocalDate begin, LocalDate end) {


        // 创建日期范围的日期列表
        List<LocalDate> localDates = begin.datesUntil(end.plusDays(1)).collect(Collectors.toList());


        List<Double> turnoverList = localDates.stream()
                .map(localDate -> {
                    // 创建当天开始和结束的时间戳
                    LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
                    LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);

                    // 创建查询参数的Map
                    Map<String, Object> paramMap = new HashMap<>();
                    paramMap.put("beginTime", beginTime);
                    paramMap.put("endTime", endTime);
                    paramMap.put("status", Orders.COMPLETED);

                    // 调用orderMapper的sumByMap方法获取当天的营业额
                    Double turnover = orderMapper.sumByMap(paramMap);

                    // 如果营业额为null，将其设置为0.0
                    return turnover != null ? turnover : 0.0;
                })
                .collect(Collectors.toList());

        // 将日期列表转换为逗号分隔的字符串
        String dateList = localDates.stream()
                .map(LocalDate::toString)
                .collect(Collectors.joining(","));

        // 将营业额列表转换为逗号分隔的字符串
        String turnoverListStr = turnoverList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(","));

        // 创建TurnoverReportVO对象并返回
        return new TurnoverReportVO(dateList, turnoverListStr);

    }

    /**
     * 查询用户统计用户统计
     *
     * @param begin
     * @param end
     * @return
     */
    public UserReportVO getUserStatistics(LocalDate begin, LocalDate end) {
        // 创建日期范围的日期列表
        List<LocalDate> localDates = begin.datesUntil(end.plusDays(1)).collect(Collectors.toList());        //新增用户数列表，以逗号分隔
        List<Integer> newUserList = new ArrayList<>();
        //总用户量列表，以逗号分隔
        List<Integer> totalUserList = new ArrayList<>();

        localDates.forEach(localDate -> {
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("endTime", endTime);
            Integer totalUser = userMapper.countByMap(paramMap);
            paramMap.put("beginTime", beginTime);
            Integer newUser = userMapper.countByMap(paramMap);
            totalUser = totalUser != null ? totalUser : 0;
            newUser = newUser != null ? newUser : 0;
            newUserList.add(newUser);
            totalUserList.add(totalUser);
        });

        // 将日期列表转换为逗号分隔的字符串
        String dateListStr = localDates.stream()
                .map(LocalDate::toString)
                .collect(Collectors.joining(","));
        // 将新用户列表转换为逗号分隔的字符串
        String newUserListStr = newUserList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(","));
        // 将总列表转换为逗号分隔的字符串
        String totalUserListStr = totalUserList.stream()
                .map(Object::toString)
                .collect(Collectors.joining(","));
        return  UserReportVO.builder()
                .newUserList(newUserListStr)
                .totalUserList(totalUserListStr)
                .dateList(dateListStr).build();
    }

    /**
     * 订单统计接口
     * @param begin
     * @param end
     * @return
     */
    public OrderReportVO getOrderStatisticsVO(LocalDate begin, LocalDate end) {
        // 创建日期范围的日期列表
        List<LocalDate> localDates = begin.datesUntil(end.plusDays(1)).collect(Collectors.toList());

        // 存储订单总数和有效订单数的列表
        List<Integer> orderCountList = new ArrayList<>();
        List<Integer> validOrderCountList = new ArrayList<>();

        // 遍历日期列表
        for (LocalDate localDate : localDates) {
            // 创建开始时间和结束时间
            LocalDateTime beginTime = LocalDateTime.of(localDate, LocalTime.MIN);
            LocalDateTime endTime = LocalDateTime.of(localDate, LocalTime.MAX);

            // 创建用于查询的参数映射
            Map<String, Object> map = new HashMap<>();
            map.put("endTime", endTime);
            map.put("beginTime", beginTime);

            // 查询总订单数
            Integer totalOrder = orderMapper.countByMap(map);
            orderCountList.add(totalOrder);

            // 查询有效订单数（假设有效订单的状态是 Orders.COMPLETED）
            map.put("status", Orders.COMPLETED);
            Integer validOrder = orderMapper.countByMap(map);
            validOrderCountList.add(validOrder);
        }

        // 计算总订单数和有效订单数的总和
        Integer totalOrderCount = orderCountList.stream().reduce(Integer::sum).get();
        Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();

        // 计算订单完成率
        Double orderCompletionRate = (double) (validOrderCount) / totalOrderCount;

        // 创建并返回 OrderReportVO 对象
        return OrderReportVO.builder()
                .totalOrderCount(totalOrderCount)
                .validOrderCount(validOrderCount)
                .validOrderCountList(StringUtils.join(validOrderCountList, ",")) // 将有效订单数列表转换为逗号分隔的字符串
                .orderCountList(StringUtils.join(orderCountList, ",")) // 将订单总数列表转换为逗号分隔的字符串
                .dateList(StringUtils.join(localDates, ",")) // 将日期列表转换为逗号分隔的字符串
                .orderCompletionRate(orderCompletionRate)
                .build();
    }


    /**
     * 查询销量排名top10接口
     * @param begin
     * @param end
     * @return
     */
    public SalesTop10ReportVO getTop10(LocalDate begin, LocalDate end) {

        // 将开始日期转换为当天的最早时间
        LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);

        // 将结束日期转换为当天的最晚时间
        LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);

        // 通过 orderMapper 获取销量前10的商品信息
        List<GoodsSalesDTO> salesTop10 = orderMapper.getSalesTop10(beginTime, endTime);

        // 将商品名称列表提取出来
        List<String> names = salesTop10.stream().map(GoodsSalesDTO::getName).collect(Collectors.toList());

        // 将销量列表提取出来
        List<Integer> numbers = salesTop10.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());

        // 将商品名称列表拼接成字符串
        String nameList = StringUtils.join(names, ",");

        // 将销量列表拼接成字符串
        String numberList = StringUtils.join(numbers, ",");

        // 构建 SalesTop10ReportVO 对象并返回
        return SalesTop10ReportVO.builder()
                .nameList(nameList)
                .numberList(numberList)
                .build();
    }


    /**
     * 下载 excel
     * @param response
     */
    public void export(HttpServletResponse response) {
        // 获取最近30天的日期范围
        LocalDate dateBegin = LocalDate.now().minusDays(30);
        LocalDate dateEnd = LocalDate.now().minusDays(1);

        // 获取业务数据
        BusinessDataVO businessData = workspaceService.getBusinessData(
                LocalDateTime.of(dateBegin, LocalTime.MIN),
                LocalDateTime.of(dateEnd, LocalTime.MAX)
        );

        try (InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
             XSSFWorkbook workbook = new XSSFWorkbook(resourceAsStream)) {

            XSSFSheet sheet = workbook.getSheetAt(0);

            // 设置报表日期范围
            sheet.getRow(1).getCell(1).setCellValue("时间 :  " + dateBegin.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " ~ " + dateEnd.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));

            XSSFRow row = sheet.getRow(3);
            row.getCell(2).setCellValue(businessData.getTurnover());
            row.getCell(4).setCellValue(businessData.getOrderCompletionRate());
            row.getCell(6).setCellValue(businessData.getNewUsers());

            row = sheet.getRow(4);
            row.getCell(2).setCellValue(businessData.getValidOrderCount());
            row.getCell(4).setCellValue(businessData.getUnitPrice());

            // 填充最近30天的业务数据
            for (int i = 0; i < 30; i++) {
                LocalDate currentDate = dateBegin.plusDays(i);
                BusinessDataVO dailyData = workspaceService.getBusinessData(
                        LocalDateTime.of(currentDate, LocalTime.MIN),
                        LocalDateTime.of(currentDate, LocalTime.MAX)
                );
                row = sheet.getRow(7 + i);
                row.getCell(1).setCellValue(currentDate.toString());
                row.getCell(2).setCellValue(dailyData.getTurnover());
                row.getCell(3).setCellValue(dailyData.getValidOrderCount());
                row.getCell(4).setCellValue(dailyData.getOrderCompletionRate());
                row.getCell(5).setCellValue(dailyData.getUnitPrice());
                row.getCell(6).setCellValue(dailyData.getNewUsers());
            }

            // 输出到响应流
            ServletOutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }



}
